package org.jeecg.modules.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.wms.entity.*;
import org.jeecg.modules.wms.mapper.FinishedGoodsOutboundMapper;
import org.jeecg.modules.wms.mapper.FinishedGoodsInventoryMapper;
import org.jeecg.modules.wms.service.*;
import org.jeecg.modules.oms.entity.ProductSalesOrder;
import org.jeecg.modules.oms.service.IProductSalesOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;

/**
 * 成品出库单Service实现类
 */
@Service
public class FinishedGoodsOutboundServiceImpl extends ServiceImpl<FinishedGoodsOutboundMapper, FinishedGoodsOutbound> 
        implements IFinishedGoodsOutboundService {

    @Autowired
    private FinishedGoodsOutboundMapper outboundMapper;
    
    @Autowired
    private IFinishedGoodsOutboundDetailService detailService;
    
    @Autowired
    private FinishedGoodsInventoryMapper inventoryMapper;

    @Override
    public IPage<FinishedGoodsOutbound> queryOutboundList(Page<FinishedGoodsOutbound> page, FinishedGoodsOutbound query) {
        return outboundMapper.selectOutboundPage(page, query);
    }

    @Override
    public List<FinishedGoodsOutbound> queryByCustomerId(String customerId) {
        String tenantId = oConvertUtils.getString(LoginUser.class, "tenantId");
        return outboundMapper.selectByCustomerId(customerId, tenantId);
    }

    @Override
    public List<FinishedGoodsOutbound> queryByStatus(Integer status) {
        String tenantId = oConvertUtils.getString(LoginUser.class, "tenantId");
        return outboundMapper.selectByStatus(status, tenantId);
    }

    @Override
    public Long countByStatus(Integer status) {
        String tenantId = oConvertUtils.getString(LoginUser.class, "tenantId");
        return outboundMapper.countByStatus(status, tenantId);
    }

    @Override
    public String generateOutboundNo() {
        String dateStr = String.format("%tY%<tm%<td", new Date());
        String timeStr = String.format("%tH%<tM%<tS", new Date());
        return "CP-CK-" + dateStr + "-" + timeStr;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitForAudit(String id, String submitterId) {
        FinishedGoodsOutbound outbound = this.getById(id);
        if (outbound == null) {
            throw new RuntimeException("出库单不存在");
        }
        
        if (outbound.getStatus() != 0) {
            throw new RuntimeException("只有待审核状态的出库单才能提交审核");
        }

        // 更新状态为待审核
        outbound.setStatus(0);
        outbound.setApplyTime(new Date());
        
        boolean result = this.updateById(outbound);
        
        // 提交审核成功，无需记录日志
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditOutbound(String id, Integer auditResult, String auditRemark, String auditorId, String auditorName) {
        FinishedGoodsOutbound outbound = this.getById(id);
        if (outbound == null) {
            throw new RuntimeException("出库单不存在");
        }
        
        if (outbound.getStatus() != 0) {
            throw new RuntimeException("只有待审核状态的出库单才能进行审核");
        }

        // 更新审核信息
        outbound.setStatus(auditResult); // 1-审核通过，2-审核驳回
        outbound.setAuditPersonId(auditorId);
        outbound.setAuditPersonName(auditorName);
        outbound.setAuditTime(new Date());
        outbound.setAuditRemark(auditRemark);
        
        boolean result = this.updateById(outbound);
        
        // 审核完成，无需记录日志
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelOutbound(String id, String reason, String operatorId, String operatorName) {
        FinishedGoodsOutbound outbound = this.getById(id);
        if (outbound == null) {
            throw new RuntimeException("出库单不存在");
        }
        
        if (outbound.getStatus() == 3) {
            throw new RuntimeException("已出库的出库单不能取消");
        }

        // 更新状态为已取消
        outbound.setStatus(4); // 4-已取消
        
        boolean result = this.updateById(outbound);
        
        if (result) {
            // TODO: 这里应该调用库存服务释放预留库存
            // inventoryService.releaseReservedInventory(outboundId);
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createOutboundWithDetails(FinishedGoodsOutbound outbound) {
        try {
            // 生成出库单号
            String outboundNo = generateOutboundNo();
            outbound.setOutboundNo(outboundNo);
            outbound.setStatus(0); // 待审核
            outbound.setApplyTime(new Date());
            
            // 保存出库单主表
            this.save(outbound);
            
            // 保存出库明细（根据订单明细信息查询库存）
            if (outbound.getOrderDetailList() != null &&
                !outbound.getOrderDetailList().isEmpty()) {
                
                for (FinishedGoodsOutbound.OrderDetailInfo orderDetail : outbound.getOrderDetailList()) {
                    // 根据订单编号和订单明细ID查询对应的库存信息
                    List<FinishedGoodsInventory> inventoryList = inventoryMapper.selectByOrderNoAndDetailId(
                        orderDetail.getOrderNo(), orderDetail.getOrderDetailId());
                    
                    if (inventoryList != null && !inventoryList.isEmpty()) {
                        for (FinishedGoodsInventory inventory : inventoryList) {
                            // 根据库存信息创建出库明细
                            FinishedGoodsOutboundDetail detail = new FinishedGoodsOutboundDetail();
                            detail.setOutboundId(outbound.getId());
                            detail.setInventoryId(inventory.getId());
                            detail.setOrderId(outbound.getOrderId());
                            detail.setOrderDetailId(orderDetail.getOrderDetailId());
                            detail.setPlannedQuantity(orderDetail.getPlannedQuantity());
                            detail.setActualQuantity(0); // 初始实际出库数量为0
                            detail.setRemark(orderDetail.getRemark());
                            detail.setCreateTime(new Date());
                            
                            detailService.save(detail);
                        }
                    }else {
                        throw new RuntimeException("订单明细对应的库存信息不存在");
                    }
                }
            }
            
            return outbound.getId();
        } catch (Exception e) {
            throw new RuntimeException("创建出库单失败: " + e.getMessage(), e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean executeOutbound(String outboundId, List<Map<String, Object>> details, String userId, String userName) {
        try {
            // 获取出库单
            FinishedGoodsOutbound outbound = this.getById(outboundId);
            if (outbound == null) {
                throw new RuntimeException("出库单不存在");
            }

            // 检查状态
            if (outbound.getStatus() != 1) {
                throw new RuntimeException("只有已审核的出库单才能执行出库");
            }

            // 处理出库明细
            for (Map<String, Object> detail : details) {
                String detailId = (String) detail.get("detailId");
                String warehouseId = (String) detail.get("warehouseId");
                String locationId = (String) detail.get("locationId");
                Integer quantity = (Integer) detail.get("quantity");

                // 这里应该调用库存服务扣减库存
                // inventoryService.reduceInventory(warehouseId, locationId, detailId, quantity);

                // 更新出库明细的实际出库数量
                FinishedGoodsOutboundDetail outboundDetail = detailService.getById(detailId);
                if (outboundDetail != null) {
                    outboundDetail.setActualQuantity((outboundDetail.getActualQuantity() == null ? 0 : outboundDetail.getActualQuantity()) + quantity);
                    detailService.updateById(outboundDetail);
                }
            }

            // 检查是否全部出库完成
            List<FinishedGoodsOutboundDetail> allDetails = detailService.queryByOutboundId(outboundId);
            boolean allCompleted = allDetails.stream().allMatch(detail -> {
                int planned = detail.getPlannedQuantity() == null ? 0 : detail.getPlannedQuantity();
                int actual = detail.getActualQuantity() == null ? 0 : detail.getActualQuantity();
                return actual >= planned;
            });

            // 更新出库单状态
            if (allCompleted) {
                outbound.setStatus(3); // 已完成
            } else {
                outbound.setStatus(2); // 部分出库
            }
            outbound.setOutboundTime(new Date());

            return this.updateById(outbound);
        } catch (Exception e) {
            throw new RuntimeException("执行出库失败: " + e.getMessage(), e);
        }
    }

    @Autowired
    private IWmsInventoryService inventoryService;
    
    @Autowired
    private IFinishedGoodsInventoryLogService inventoryLogService;
    
    @Autowired
    private IWmsWarehouseLocationService locationService;
    
    @Autowired
    private IProductSalesOrderService orderService;

    @Autowired
    private IFinishedGoodsInboundService inboundService;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean oneClickOutbound(String outboundId, String userId, String userName) {
        try {
            // 1. 获取出库单基本信息
            FinishedGoodsOutbound outbound = this.getById(outboundId);
            if (outbound == null) {
                throw new RuntimeException("出库单不存在");
            }

            // 检查状态
            if (outbound.getStatus() != 1) {
                throw new RuntimeException("只有已审核的出库单才能执行出库");
            }

            // 2. 根据出库单ID查询出库详情
            List<FinishedGoodsOutboundDetail> detailList = detailService.queryByOutboundId(outboundId);
            if (detailList == null || detailList.isEmpty()) {
                throw new RuntimeException("出库单无明细信息");
            }
            
            // 用于统计订单出库情况
            Set<String> processedOrders = new HashSet<>();
            
            // 3. 处理每个出库明细
            for (FinishedGoodsOutboundDetail detail : detailList) {
                // 根据库存ID获取库存信息
                FinishedGoodsInventory inventory = inventoryMapper.selectById(detail.getInventoryId());
                if (inventory == null) {
                    throw new RuntimeException("库存信息不存在，库存ID: " + detail.getInventoryId());
                }
                
                // 4. 保存库存变更记录
                FinishedGoodsInventoryLog log = new FinishedGoodsInventoryLog();
                log.setInventoryId(inventory.getId());
                log.setOrderNo(inventory.getOrderNo());
                log.setOperationType(2); // 2-出库
                log.setOperationQuantity(inventory.getAvailableQuantity());
                log.setBeforeQuantity(inventory.getAvailableQuantity());
                log.setAfterQuantity(0); // 全部出库后数量为0
                log.setOperationReason("一键出库");
                log.setRelatedDocNo(outbound.getOutboundNo());
                log.setOperatorId(userId);
                log.setOperatorName(userName);
                log.setTenantId(inventory.getTenantId());
                log.setCreateTime(new Date());
                inventoryLogService.save(log);
                
                // 5. 删除库存信息（全部出库）
                inventoryMapper.deleteById(inventory.getId());
                
                // 6. 检查库位上是否还有其他库存，若无则修改库位状态为空闲
                LambdaQueryWrapper<FinishedGoodsInventory> locationQuery = new LambdaQueryWrapper<>();
                locationQuery.eq(FinishedGoodsInventory::getWarehouseId, inventory.getWarehouseId())
                           .eq(FinishedGoodsInventory::getLocationId, inventory.getLocationId())
                           .eq(FinishedGoodsInventory::getTenantId, inventory.getTenantId());
                           
                long remainingInventoryCount = inventoryMapper.selectCount(locationQuery);
                if (remainingInventoryCount == 0) {
                    // 修改库位状态为空闲
                    WmsWarehouseLocation location = locationService.getById(inventory.getLocationId());
                    if (location != null) {
                        location.setStatus("1"); // 1-空闲
                        locationService.updateById(location);
                    }
                }
                
                // 记录已处理的订单
                if (inventory.getOrderNo() != null) {
                    processedOrders.add(inventory.getOrderNo());
                }
                
                // 更新出库明细的实际出库数量
                detail.setActualQuantity(inventory.getAvailableQuantity());
                detailService.updateById(detail);
            }
            
            // 7. 检查订单完成情况并更新订单状态
            for (String orderNo : processedOrders) {
                //判断订单的成品入库单是否全部入库
                List<FinishedGoodsInbound> inboundList = inboundService.list(new LambdaQueryWrapper<FinishedGoodsInbound>()
                        .eq(FinishedGoodsInbound::getOrderId,outbound.getOrderId()));
                boolean allInboundCompleted = true;
                if(!inboundList.isEmpty() && inboundList.size() > 0){
                    for (FinishedGoodsInbound inbound : inboundList) {
                        if(inbound.getInboundStatus() != 2){
                            allInboundCompleted = false;
                            break;
                        }
                    }
                }
                if(allInboundCompleted){
                    // 查询该订单是否还有其他成品库存
                    LambdaQueryWrapper<FinishedGoodsInventory> orderQuery = new LambdaQueryWrapper<>();
                    orderQuery.eq(FinishedGoodsInventory::getOrderNo, orderNo);

                    long remainingOrderInventory = inventoryMapper.selectCount(orderQuery);

                    if (remainingOrderInventory == 0) {
                        orderService.updateOrderStatus(outbound.getOrderId(),10,11,userId,"成品出库完成");
                    }
                }
            }

            // 8. 更新出库单状态为已完成
            outbound.setStatus(3); // 3-已完成
            outbound.setOutboundTime(new Date());
            this.updateById(outbound);

            return true;
        } catch (Exception e) {
            throw new RuntimeException("一键出库失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Result<String> deleteById(String id) {
        FinishedGoodsOutbound outbound = this.getById(id);
        if (outbound == null) {
            return Result.error("出库单不存在");
        }

        if (outbound.getStatus() == 3) {
            return Result.error("已出库的出库单不能删除");
        }

        this.removeById(id);
        //删除入库单下的所有明细
        detailService.remove(new LambdaQueryWrapper<FinishedGoodsOutboundDetail>().eq(FinishedGoodsOutboundDetail::getOutboundId, id));
        return Result.OK("删除成功!");
    }
}
